using System;
using System.Collections;
using System.Data;
using System.IO;
using System.Text;
using System.Web.UI.WebControls;
using PHSRAG.Insight21.Common.Pages;
using PHSRAG.Insight21.Context;
using PHSRAG.Insight21.InsightUtilities;
using PHSRAG.Insight21.Policy;
using PHSRAG.Insight21.Purchasing;
using PHSRAG.Insight21.SearchContext;
using PHSRAG.Utility;
using PurchasingReports = PHSRAG.Insight21.Purchasing.Reports;
using Constant = PHSRAG.Insight21.InsightUtilities.Constants;
using Constants = PHSRAG.Insight21.Purchasing.Constants;
using Helper = PHSRAG.WebControls.Helper;
using Utils = PHSRAG.Insight21.InsightUtilities;

namespace PHSRAG.Insight21
{
    /// <summary>
    ///   The PO Details page lists the PO/AP detailed information accessible to the current user
    ///   It displays the header, line item and distribution details for the PO/AP details.  
    ///   Line details is shown in collapsed mode and 
    ///   when user expands the line number the distribution details is shown in the expanded mode.
    /// </summary>
    public partial class PODetails : NoCachePage
    {
        #region Constants(Private)

        private const int DefaultOrderType = 0;
        private const string ExcelReportControlFilePath = "../../Purchasing/Reports/PODetailsExcel.ascx";
        private const string ExpandedTag = "--Expanded--";
        private const string POAPOrderNumberKey = "POAPOrderNumberKey_bfd899dd-fa7e-4ce7-a0d5-c92038abc1cd";
        private const string POAPOrderTypeKey = "POAPOrderTypeKey_bfd899dd-fa7e-4ce7-a0d5-c92038abc1cd";
        private const string ReferringPageKey = "ReferringPageKey_bfd899dd-fa7e-4ce7-a0d5-c92038abc1cd";
        private const string StateColName = "StateColumn";

        #endregion

        #region Instance Variables (Private)

        private ICachePolicy cachePolicy;
        private ICachePolicy pageCachePolicy;
        private ViewStateCachePolicy viewStateCachePolicy;

        #endregion

        #region Enum DataGridColumns

        #region Nested type: DataGridColumns

        /// <summary>
        /// The DataGridColumns enumeration defines values 
        /// for indexing columns in the datagrid.
        /// </summary>
        private enum DataGridColumns
        {
            Expanded, //Column for Item Expand/Collapse
            ID,
            LineNumber,
            Description,
            Category,
            AccountNumber,
            FundNumber,
            Quantity,
            UOM,
            OriginalOrderAmount,
            ExpensedToDate,
            BalanceRemaining,
            CurrentInvoiceAmt,
            InvoiceDate,
            PaidDate
        }

        #endregion

        #region Nested type: TotalColumns

        /// <summary>
        /// The TotalColumns enumeration defines values 
        /// for indexing columns in the Total datatable.
        /// </summary>
        private enum TotalColumns
        {
            OriginalOrderAmount,
            ExpensedToDate,
            BalanceRemaining,
            CurrentInvoiceAmt,
        }

        #endregion

        #endregion

        #region Private Properties

        ///<summary>Gets the Order number passed from the orginating page and cache it using pagecache policy</summary>
        private string POAPOrderNumber
        {
            get
            {
                Hashtable incomingPOData = pageCachePolicy.GetCachedObject(Keys.PODetailsPageKey) as Hashtable;
                return (incomingPOData == null || incomingPOData[POAPOrderNumberKey] == null)
                    ? string.Empty : (string) incomingPOData[POAPOrderNumberKey];
            }
            set
            {
                Hashtable h = pageCachePolicy.GetCachedObject(Keys.PODetailsPageKey) as Hashtable ?? new Hashtable();
                h[POAPOrderNumberKey] = value;
                pageCachePolicy.Cache(Keys.PODetailsPageKey, h);
            }
        }

        ///<summary>Gets the Order Type passed from the orginating page and cache it using pagecache policy.</summary>
        private int POAPOrderType
        {
            get
            {
                Hashtable incomingPOData = pageCachePolicy.GetCachedObject(Keys.PODetailsPageKey) as Hashtable;
                return (incomingPOData == null || incomingPOData[POAPOrderTypeKey] == null)
                    ? DefaultOrderType : (int) incomingPOData[POAPOrderTypeKey];
            }
            set
            {
                Hashtable h = pageCachePolicy.GetCachedObject(Keys.PODetailsPageKey) as Hashtable ?? new Hashtable();
                h[POAPOrderTypeKey] = value;
                pageCachePolicy.Cache(Keys.PODetailsPageKey, h);
            }
        }

        /// <summary>
        /// Gets the POAPDetails object.
        /// Call the static method GetCachedObject to get POAPDetails object from  the cache. 
        /// Check if the object is null or incoming OrderNumber is not equal to cached OrderNumber,
        ///  then instantiate  the POAPDetailsobject and cache it otherwise return  the cached object.
        ///</summary>
        private POAPDetails POAPDetail
        {
            get
            {
                POAPDetails poapDetails =
                    ResultsCache.GetObject(cachePolicy, POAPDetails.CacheKey) as POAPDetails;

                if (poapDetails == null || poapDetails.OrderNumber != POAPOrderNumber)
                {
                    poapDetails = new POAPDetails();
                    UserContext userContext = cachePolicy.GetCachedObject(UserContext.CacheKey) as UserContext;
                    if (userContext == null)
                    {
                        throw new Exception("Unable to retrieve the UserContext from cache");
                    }
                    poapDetails.Load(DataAccess.GetConnectionString(),
                        userContext.DomainUserId,
                        POAPOrderNumber,
                        POAPOrderType);

                    ResultsCache.SetObject(cachePolicy, POAPDetails.CacheKey, poapDetails);
                }

                return poapDetails;
            }
        }

        /// <summary>
        /// Get and Set the referring page that brought us to the PODetails page. Using the value for the referring
        /// page, the navigation bars to be displayed on this page is decided.
        /// </summary>
        private string ReferringPage
        {
            get
            {
                object o = viewStateCachePolicy.GetCachedObject(ReferringPageKey);
                return (o == null) ? string.Empty : (string) o;
            }
            set { viewStateCachePolicy.Cache(ReferringPageKey, value); }
        }

        #endregion

        #region Private Methods

        /// <summary>
        /// Formats the currency columns in the datagrid with different styles for positive and 
        /// negative values.
        /// Checking whether celltext value is not ;&nbsp then convert into decimal.
        /// </summary>
        /// <param name="cell"> Cell which need to be formatted</param>
        private void FormatDataColumns(TableCell cell)
        {
            string celltext = cell.Text;

            decimal amount = celltext != Constants.Space ? Convert.ToDecimal(celltext) : 0;
            cell.CssClass = amount < 0 ? Constants.DeficitStyle : Constants.CurrencyStyle;
            cell.Text = celltext != Constants.Space ? amount.ToString("c", Helper.ChooseDecimals(2)) : celltext;
        }

        /// <summary>
        /// Load the Header and Line information.
        /// </summary>
        private void LoadData()
        {
            try
            {
                Hashtable incomingPOData = pageCachePolicy.GetCachedObject(Keys.IncomingDataKey) as Hashtable;

                string incomingOrderNumber = (incomingPOData == null || incomingPOData[Keys.POAPOrderNumberKey] == null)
                    ? string.Empty : (string) incomingPOData[Keys.POAPOrderNumberKey];

                int incomingOrderType = (incomingPOData == null || incomingPOData[Keys.POAPOrderTypeKey] == null)
                    ? DefaultOrderType : (int) incomingPOData[Keys.POAPOrderTypeKey];

                POAPOrderNumber = incomingOrderNumber;
                POAPOrderType = incomingOrderType;
                //Uncache
                pageCachePolicy.UnCache(Keys.IncomingDataKey);

                LoadOrderHeader();
                LoadOrderLine();
            }
            catch (Exception e)
            {
                annunciator.Message = String.Format("{0} Error while loading the Header and Line Controls.", ExceptionReport.GetExceptionInfo(e, false));
            }
        }

        /// <summary>
        ///This function is used to assign the Order header information 
        ///to the header control.
        ///The values are assigned only when OrderHeader data table has values.
        /// </summary>
        private void LoadOrderHeader()
        {
            headerGrid.DataSource = POAPDetail.GetDataContainer().Tables[Constants.POAPDetailsHeaderDataTableName];
            headerGrid.DataBind();
            headerAsOfDate.Text = DateTime.Today.ToShortDateString();
        }

        /// <summary>
        /// This function is used to bind the Line information to the expaned grid.
        /// </summary>
        private void LoadOrderLine()
        {
            expandingDataGrid.DataSource = POAPDetail.GetDataContainer().Tables[Constants.POAPDetailsDataTableName];
            expandingDataGrid.DataBind();
            lineAsOfDate.Text = DateTime.Today.ToShortDateString();
        }

        /// <summary>
        /// Removes the child rows from the master table and adds a column to detail(account) table,
        /// based on the type of account type. The column is added to facilitate conditional formula
        /// in xslt.
        /// </summary>
        /// <returns></returns>
        private DataSet PrepareTablesForDownload()
        {
            DataTableCollection poDetailsTables = POAPDetail.GetDataContainer().Tables;
            DataSet trimmedPODetails = new DataSet();

            foreach (DataTable dataTable in poDetailsTables)
            {
                trimmedPODetails.Tables.Add(dataTable.Copy());
            }

            DataTable line = trimmedPODetails.Tables[Constants.POAPDetailsDataTableName];
            DataTable distribTable = trimmedPODetails.Tables[Constants.POAPDetailsDistribDataTableName];
            DataRowCollection distribRows = distribTable.Rows;
            foreach (DataRow distrib in distribRows)
            {
                DataRow[] expandedRows = line.Select(String.Format("{0} = {1} AND {2} = '{3}'",
                    Constants.IDColName, distrib[Constants.IDColName],
                    Constants.LineColName, distrib[Constants.LineColName]));

                foreach (DataRow expandedRow in expandedRows)
                {
                    line.Rows.Remove(expandedRow);
                }
            }
            trimmedPODetails.AcceptChanges();
            return trimmedPODetails;
        }

        #endregion

        #region Event handlers

        /// <summary>
        /// Handler for the event raised when the page is being loaded.
        /// Initialize the bread crumb control and load the data grid with the data.
        /// </summary>
        /// <param name="sender">Summary page which raised the event</param>
        /// <param name="e">Arguments associated with the event</param>
        protected void OnPageLoad(object sender, EventArgs e)
        {
            try
            {
                annunciator.Title = annunciator.Message = string.Empty;

                string referringPage = (IsPostBack) ? ReferringPage : Path.GetFileName(Request.UrlReferrer.LocalPath);
                //Po Detail or colappsed is decide report host page based on data 
                reportDownload.SQLReportName = "PoAPDetails";
                if (insightHeader.ModuleName == Constant.Modules.Agreements)
                {
                    purchasingSubModuleNavigation.Visible = false;
                    if (referringPage == Constant.ModulePages.TransactionOverview)
                    {
                        agreementDetailsSubNavigation.Visible = false;
                        agreementsSubNavigation.Visible = true;
                        agreementsSubNavigation.EnableOverviewNavigation = true;
                    }
                    else if (referringPage == Constant.ModulePages.TransactionDetails)
                    {
                        agreementsSubNavigation.EnableOverviewNavigation = false;
                        agreementDetailsSubNavigation.Visible = true;
                    }

                    ReferringPage = referringPage;
                }
                else
                {
                    agreementDetailsSubNavigation.Visible = false;
                    agreementsSubNavigation.Visible = false;
                    ReferringPage = insightHeader.ModuleName;
                }

                if (!IsPostBack)
                {
                    breadCrumb.Add("PO Details", Settings.GetKeyValue("SubNavigation.PurchasingDetails.PODetailsURL", string.Empty),
                        (insightHeader.ModuleName == Constant.Modules.Agreements)
                            ? Settings.GetKeyValue("BreadCrumb.SubDetailPageLevel", Constants.DefaultSubDetailPageLevelValue)
                            : Settings.GetKeyValue("BreadCrumb.DetailPageLevel", Constants.DefaultDetailPageLevelValue));

                    LoadData();
                }
                else
                {
                    // hack: stops additional +/- icons being added incorrectly after clicking
                    // on one of the download choices
                    expandingDataGrid.DataBind();
                }
            }
            catch (Exception ex)
            {
                annunciator.Message = ExceptionReport.GetExceptionInfo(ex, false);
            }
        }

        /// <summary>
        /// Handler for event raised when each data grid item is bound to a datacolumn.
        /// Check for negative values for the currency fields and apply appropriate style if negative.
        /// Formatting is applied to Item types and Alternating Item types.
        /// </summary>
        /// <param name="sender">Control which raised the event</param>
        /// <param name="e">Argument associated with the event</param>
        private void OnItemDataBound(object sender, DataGridItemEventArgs e)
        {
            try
            {
                DataGridItem item = e.Item;
                if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
                {
                    DataRowView row = (DataRowView) item.DataItem;
                    FormatDataColumns(e.Item.Cells[(int) DataGridColumns.OriginalOrderAmount]);
                    FormatDataColumns(e.Item.Cells[(int) DataGridColumns.ExpensedToDate]);
                    FormatDataColumns(e.Item.Cells[(int) DataGridColumns.BalanceRemaining]);
                    FormatDataColumns(e.Item.Cells[(int) DataGridColumns.CurrentInvoiceAmt]);
                    if (row[StateColName] != DBNull.Value && row[StateColName].ToString() != ExpandedTag)
                    {
                        item.CssClass = item.ItemType == ListItemType.Item ? Constants.GridItemExpanded : Constants.GridAltItemExpanded;
                    }
                }
                else if (e.Item.ItemType == ListItemType.Footer)
                {
                    DataRow totals = POAPDetail.GetDataContainer().Tables[Constants.POAPDetailsTotals].Rows[0];
                    e.Item.Cells[(int) DataGridColumns.Expanded].Text = "Totals";
                    e.Item.Cells[(int) DataGridColumns.OriginalOrderAmount].Text = Convert.ToDecimal(totals[(int) TotalColumns.OriginalOrderAmount]).ToString();
                    e.Item.Cells[(int) DataGridColumns.ExpensedToDate].Text = Convert.ToDecimal(totals[(int) TotalColumns.ExpensedToDate]).ToString();
                    e.Item.Cells[(int) DataGridColumns.BalanceRemaining].Text = Convert.ToDecimal(totals[(int) TotalColumns.BalanceRemaining]).ToString();
                    e.Item.Cells[(int) DataGridColumns.CurrentInvoiceAmt].Text = Convert.ToDecimal(totals[(int) TotalColumns.CurrentInvoiceAmt]).ToString();
                    //Format the styles.
                    FormatDataColumns(e.Item.Cells[(int) DataGridColumns.OriginalOrderAmount]);
                    FormatDataColumns(e.Item.Cells[(int) DataGridColumns.ExpensedToDate]);
                    FormatDataColumns(e.Item.Cells[(int) DataGridColumns.BalanceRemaining]);
                    FormatDataColumns(e.Item.Cells[(int) DataGridColumns.CurrentInvoiceAmt]);
                }
            }
            catch (Exception ex)
            {
                annunciator.Message = String.Format("{0} Amount fields are not in correct format.", ExceptionReport.GetExceptionInfo(ex, false));
            }
        }

        /// <summary>
        /// Invoked by the download bar when it catches an exception.
        /// </summary>
        /// <param name="sender">Control which raised the event</param>
        /// <param name="e">Argument associated with the event</param>
        private void OnDownloadFailed(object sender, CommandEventArgs e)
        {
            annunciator.Title = "Following error(s) occurred while downloading";
            annunciator.Message = ExceptionReport.GetExceptionInfo((Exception) e.CommandArgument, false);
        }

        /// <summary>
        /// Handles Send By Email button clicks by preparing a MailMessage to send back to the InsightDownloadBar control
        /// </summary>
        /// <remarks>
        /// This method generates the raw information needed for the InsightDownloadBar to process and send an e-mail
        /// with a link back to the page with the correct session settings.
        /// This page stores OrderNumber and OrderType into the database.
        /// </remarks>
        public void OnSendByEmail(out string webConfigURLKey, out int queryID, out Hashtable summaryInfo)
        {
            try
            {
                webConfigURLKey = "SubNavigation.PurchasingDetails.PODetailsURL";
                string query = String.Format("{0}={1}&{2}={3}",
                    Keys.POAPOrderNumberKey, POAPOrderNumber,
                    Keys.POAPOrderTypeKey, POAPOrderType);
                queryID = POAPDetails.GetQueryID(query);
                //Summary Information.
                DataTable total = POAPDetail.GetDataContainer().Tables[Constants.POAPDetailsTotals];
                summaryInfo = new Hashtable();
                if (total.Rows.Count > 0)
                {
                    summaryInfo = new Hashtable();
                    summaryInfo[Email.OriginalOrderAmountKey] = total.Rows[0][(int) TotalColumns.OriginalOrderAmount].ToString();
                    summaryInfo[Email.OriginalOrderAmountPaidToDateKey] = total.Rows[0][(int) TotalColumns.ExpensedToDate].ToString();
                    summaryInfo[Email.BalanceRemainingKey] = total.Rows[0][(int) TotalColumns.BalanceRemaining].ToString();
                    summaryInfo[Email.CurrentInvoiceAmountKey] = total.Rows[0][(int) TotalColumns.CurrentInvoiceAmt].ToString();
                }
            }
            catch (Exception e)
            {
                webConfigURLKey = null;
                queryID = -1;
                summaryInfo = null;
                ExceptionReport.WriteToEventLog("Send By Email click handler", e, true, ExceptionReport.ReportType.Error);
            }
        }

        /// <summary>
        /// Handles the event whenever a row is either expanded or collapsed.
        /// </summary>
        /// <remarks>
        /// This Method will return Expanded DataSet(Order Distribution ) for display.
        /// </remarks>		
        private object OnItemExpanded(string key)
        {
            DataTable childTable = POAPDetail.GetDataContainer().Tables[Constants.POAPDetailsDistribDataTableName];
            DataRow[] childRows = childTable.Select(String.Format("ID='{0}'", key));
            DataTable returnTable = childTable.Clone();
            foreach (DataRow dr in childRows)
            {
                returnTable.ImportRow(dr);
            }
            return returnTable;
        }

        /// <summary>
        /// Resets the subnavigation selected link(s) before the 
        /// header performs a redirect.
        /// </summary>
        /// <param name="sender">Control which rasied the event.</param>
        /// <param name="e">Arguments associated with the event.</param>
        private void OnHeaderNavigate(object sender, CommandEventArgs e)
        {
            purchasingSubModuleNavigation.Reset();
            agreementDetailsSubNavigation.Reset();
            agreementsSubNavigation.Reset();
        }

        #endregion

        #region Web Form Designer generated code

        protected override void OnInit(EventArgs e)
        {
            InitializeComponent();
            base.OnInit(e);
            pageCachePolicy = (Policy.ICachePolicy) Session[Policy.Names.PageCachePolicyKey];
            cachePolicy = (Policy.ICachePolicy) Session[Policy.Names.CachePolicyKey];
            viewStateCachePolicy = new PHSRAG.Insight21.Policy.ViewStateCachePolicy(this.ViewState);
            expandingDataGrid.ItemExpanded += new PHSRAG.WebControls.ExpandingDataGrid.ItemExpandedHandler(OnItemExpanded);

            this.reportDownload.FailedAction += new CommandEventHandler(OnDownloadFailed);
        }

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.insightHeader.Navigate += new System.Web.UI.WebControls.CommandEventHandler(this.OnHeaderNavigate);
            this.reportDownload.SendByEmail += new PHSRAG.WebControls.DownloadBar.EmailEventHandler(this.OnSendByEmail);
            this.expandingDataGrid.ItemDataBound += new System.Web.UI.WebControls.DataGridItemEventHandler(this.OnItemDataBound);
            this.Load += new System.EventHandler(this.OnPageLoad);
        }

        /// <summary>
        /// Adds refresh dates currently visible on the page to the search criteria string
        /// to be passed down to reports. The criteria does not persist to the SearchCriteria
        /// object.
        /// </summary>
        /// <param name="searchCriteria">Object containing search criteria.</param>
        /// <returns>A string representation of search criteria. </returns>
        /// --added 12-05-2007 for new DownloadToExcel method JML
        private string AddRefreshDatesToCriteria(SearchCriteria searchCriteria)
        {
            StringBuilder criteria = new StringBuilder(searchCriteria.ToString(";"));
            if (refreshDates.SalaryAsOfDateVisible)
            {
                criteria.AppendFormat("Last Salary Post|{0};", refreshDates.SalaryAsOfDate.ToShortDateString());
            }
            if (refreshDates.GLAsOfDateVisible)
            {
                criteria.AppendFormat("Last GL Post|{0};", refreshDates.GLPostAsOfDate.ToShortDateString());
            }
            if (refreshDates.POAPAsOfDateVisible)
            {
                criteria.AppendFormat("Last PO/AP Post|{0};", refreshDates.POAPAsOfDate.ToShortDateString());
            }
            return criteria.ToString();
        }

        #endregion
    }
}